# Copyright (c) HySoP 2011-2024
#
# This file is part of HySoP software.
# See "https://particle_methods.gricad-pages.univ-grenoble-alpes.fr/hysop-doc/"
# for further info.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
@file diffusion.py
Diffusion operator generator.
"""
from hysop.constants import Implementation, HYSOP_REAL
from hysop.tools.htypes import check_instance, first_not_None
from hysop.tools.henum import EnumFactory
from hysop.tools.decorators import debug
from hysop.fields.continuous_field import Field
from hysop.topology.cartesian_descriptor import CartesianTopologyDescriptors
from hysop.parameters.scalar_parameter import ScalarParameter
from hysop.operator.base.spectral_operator import SpectralComputationalGraphNodeFrontend
from hysop.backend.host.python.operator.diffusion import PythonDiffusion
try:
from hysop.backend.device.opencl.operator.diffusion import OpenClDiffusion
except ImportError:
OpenClDiffusion = None
try:
from hysop.backend.host.fortran.operator.diffusion import DiffusionFFTW
except ImportError:
DiffusionFFTW = None
[docs]
class Diffusion(SpectralComputationalGraphNodeFrontend):
"""
Interface the diffusion solver.
Available implementations are: FORTRAN: FFTW based solver (legacy fortran)
PYTHON: generic python fft based solver (pyfftw, scipy or numpy)
OPENCL: generic opencl fft based solver (gpyfft)
"""
[docs]
@classmethod
def implementations(cls):
__implementations = {
Implementation.PYTHON: PythonDiffusion,
}
if not OpenClDiffusion is None:
__implementations.update(
{
Implementation.OPENCL: OpenClDiffusion,
}
)
if not DiffusionFFTW is None:
__implementations.update(
{
Implementation.FORTRAN: DiffusionFFTW,
}
)
return __implementations
[docs]
@classmethod
def default_implementation(cls):
return Implementation.PYTHON
@debug
def __new__(
cls,
Fin,
variables,
nu,
dt,
Fout=None,
implementation=None,
base_kwds=None,
**kwds,
):
base_kwds = first_not_None(base_kwds, {})
return super().__new__(
cls,
Fin=Fin,
Fout=Fout,
variables=variables,
nu=nu,
dt=dt,
implementation=implementation,
base_kwds=base_kwds,
**kwds,
)
@debug
def __init__(
self,
Fin,
variables,
nu,
dt,
Fout=None,
implementation=None,
base_kwds=None,
**kwds,
):
"""
Initialize a Poisson operator frontend.
Solves dF/dt = nu * Laplacian(F)
Parameters
----------
Fin: field
input field that should be diffused
Fout: field, optional, defaults to none
output field that should be diffused.
if None this will be set to Fin.
variables: dict
dictionary of fields as keys and topologies as values.
nu: float or ScalarParameter
Some implementations may only offer scalar nu.
dt: ScalarParameter
Timestep parameter that will be used for time integration.
implementation: Implementation, optional, defaults to None
target implementation, should be contained in available_implementations().
If None, implementation will be set to default_implementation().
base_kwds: dict, optional, defaults to None
Base class keywords arguments.
If None, an empty dict will be passed.
kwds:
Keywords arguments that will be passed towards implementation
poisson operator __init__.
Notes
-----
A diffusion operator implementation should at least support
the hysop.operator.base.diffusion.DiffusionBase interface.
"""
Fout = first_not_None(Fout, Fin)
base_kwds = first_not_None(base_kwds, {})
check_instance(Fin, Field)
check_instance(Fout, Field)
check_instance(variables, dict, keys=Field, values=CartesianTopologyDescriptors)
check_instance(base_kwds, dict, keys=str)
check_instance(dt, ScalarParameter)
check_instance(nu, (float, ScalarParameter))
if not isinstance(nu, ScalarParameter):
nu = ScalarParameter(
name="nu", dtype=HYSOP_REAL, initial_value=nu, quiet=True
)
super().__init__(
Fin=Fin,
Fout=Fout,
variables=variables,
nu=nu,
dt=dt,
implementation=implementation,
base_kwds=base_kwds,
**kwds,
)